package io.renren.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.renren.dao.ApplicationDao;
import io.renren.entity.*;
import io.renren.service.CheckCodeService;
import io.renren.util.*;
import io.renren.vo.RespModel;
import net.jodah.expiringmap.ExpiringMap;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


/**
 * 验证码
 *
 * @author levitian
 *
 */
@Service
@ConfigurationProperties
@PropertySource(value = {"classpath:smsConfig.properties"})
public class CheckCodeServiceImpl implements CheckCodeService {

    private static final Logger logger = LoggerFactory.getLogger(CheckCodeServiceImpl.class);

//    @Value("${SMS_MSG_PREFIX}")
    private String SMS_MSG_PREFIX;
//    @Value("${SMS_MSG_MIDDLE}")
    private String SMS_MSG_MIDDLE;
//    @Value("${SMS_MSG_SUFFIX}")
    private String SMS_MSG_SUFFIX;

//    @Value("${LOCK_WAITTIME}")
    private String LOCK_WAITTIME;
//    @Value("${SMSURL}")
    private String SMSURL;

    @Autowired
    private ApplicationDao applicationDao;

    public void setApplicationDao(ApplicationDao applicationDao) {
        this.applicationDao = applicationDao;
    }
    /**
     *
     */
    @Override
    public RespModel<SmsCheckCodeOutputModel> generateSmsCode(SmsCheckCodeInputModel smsCheckCodeInputModel) {
        if (smsCheckCodeInputModel == null
                || StringUtils.isBlank(smsCheckCodeInputModel.getPhone())
                || StringUtils.isBlank(smsCheckCodeInputModel.getApplicationId())) {
            RespModel<SmsCheckCodeOutputModel> resp = new RespModel("failed", "406", "PARAM IS MISSING",null);
            return resp;
        }

        // 查询application是否存在
        Application application = applicationDao.findOne(smsCheckCodeInputModel.getApplicationId());
        if (application == null) {
            RespModel<SmsCheckCodeOutputModel> resp = new RespModel("failed", "405","NO SUCH APPLICATION", null);
            return resp;
        }

        // 生成6位验证码
        String authenCode = RandomCodeUtil.getRandomCode();
        int expireTime = 30;
        if (smsCheckCodeInputModel.getExpireTime() > 0) {
            expireTime = smsCheckCodeInputModel.getExpireTime();
        }
        String msg = SMS_MSG_PREFIX + authenCode + SMS_MSG_MIDDLE + expireTime + SMS_MSG_SUFFIX;
        logger.debug("sms msg-------------:" + msg);

        // 发送手机验证码
        String smsresult = new SmsSendUtil(SMSURL,
                smsCheckCodeInputModel.getApplicationId(),
                smsCheckCodeInputModel.getPhone(), msg, "reg").execute();
        logger.debug("sms msg send result:" + smsresult);
        // XXX
        if (!smsresult.equals("success")) {
            RespModel<SmsCheckCodeOutputModel> resp = new RespModel("failed", "500","INTERNAL SERVER ERROR", null);
            return resp;
        }

        // 将sms验证码和对应的uuid存入ExpiringMap
        ExpiringMap<String, CheckCodeModel> em = ExpiringMapUtil.expiringMap;
        String uuid = UUID.randomUUID().toString();
        CheckCodeModel ccm = new CheckCodeModel();
        ccm.setCheckcode(authenCode);
        ccm.setId(smsCheckCodeInputModel.getPhone());
        em.put(uuid, ccm);
        // return
        RespModel<SmsCheckCodeOutputModel> resp = new RespModel("success", "", "",new SmsCheckCodeOutputModel(uuid));
        return resp;
    }

    /**
     * 生成短信验证码---用httpClient实现
     *
     * @param smsCheckCodeInputModel
     * @return
     */
    public RespModel<SmsCheckCodeOutputModel> getSmsCode(SmsCheckCodeInputModel smsCheckCodeInputModel){
        if (smsCheckCodeInputModel == null
                || StringUtils.isBlank(smsCheckCodeInputModel.getPhone())
                || StringUtils.isBlank(smsCheckCodeInputModel.getApplicationId())) {
            RespModel<SmsCheckCodeOutputModel> resp = new RespModel("failed", "406", "PARAM IS MISSING",null);
            return resp;
        }

        // 查询application是否存在
        Application application = applicationDao.selectById(smsCheckCodeInputModel.getApplicationId());
        if (application == null) {
            RespModel<SmsCheckCodeOutputModel> resp = new RespModel("failed", "405","NO SUCH APPLICATION", null);
            return resp;
        }

        // 生成6位验证码
        String authenCode = RandomCodeUtil.getRandomCode();
        int expireTime = 30;
        if (smsCheckCodeInputModel.getExpireTime() > 0) {
            expireTime = smsCheckCodeInputModel.getExpireTime();
        }

        //发送手机验证码
        Map<String,Object> argsMap = new HashMap<String,Object>();
        argsMap.put("applicationId", smsCheckCodeInputModel.getApplicationId());
        argsMap.put("message", "您的验证码是" + authenCode + ",请您于5分钟内输入");
        argsMap.put("phone", smsCheckCodeInputModel.getPhone());
        argsMap.put("type", "0");
        String argsStr = JSON.toJSONString(argsMap);
        String outputMsg = HttpClientUtil.httpRequest(SMSURL , argsStr);
        JSONObject jsonObject = JSON.parseObject(outputMsg);
        String smsresult = jsonObject.getString("status");

        if (!smsresult.equals("success")) {
            RespModel<SmsCheckCodeOutputModel> resp = new RespModel("failed", "500","INTERNAL SERVER ERROR", null);
            return resp;
        }

        // 将sms验证码和对应的uuid存入ExpiringMap
        ExpiringMap<String, CheckCodeModel> em = ExpiringMapUtil.expiringMap;
        String uuid = UUID.randomUUID().toString();
        CheckCodeModel ccm = new CheckCodeModel();
        ccm.setCheckcode(authenCode);
        ccm.setId(smsCheckCodeInputModel.getPhone());
        em.put(uuid, ccm);
        RespModel<SmsCheckCodeOutputModel> resp = new RespModel<SmsCheckCodeOutputModel>("success", "", "",new SmsCheckCodeOutputModel(uuid));
        return resp;
    }

    /**
     * 生成图片验证码
     * @param imageCheckCodeInputMode
     * @return
     */
    @Override
    public RespModel<ImageCheckCodeModel> generateImageCode(ImageCheckCodeInputMode imageCheckCodeInputMode) {
        try {
            CaptchaUtil cu = CaptchaUtil.getInstance();
            // width height num code
            cu.set(250, 100, 5, "0123456789");
            String imageCheckcode = cu.generateCheckcode();
            String imageBlob = cu.generateCheckImg(imageCheckcode);
            ImageCheckCodeModel icm = new ImageCheckCodeModel();
            String uuid = UUID.randomUUID().toString();
            icm.setId(uuid);
            icm.setImageBlob(imageBlob);

            ExpiringMap<String, CheckCodeModel> em = ExpiringMapUtil.expiringMap;
            CheckCodeModel ccm = new CheckCodeModel();
            ccm.setCheckcode(imageCheckcode);
            ccm.setId("");
            em.put(uuid, ccm);
            logger.info("imageCheckcode-------------:" + imageCheckcode);

            RespModel<ImageCheckCodeModel> resp = new RespModel("success", "", "", icm);
            return resp;
        } catch (IOException e) {
            logger.error("response error:", e);
            RespModel<ImageCheckCodeModel> resp = new RespModel("failed", "500","INTERNAL SERVER ERROR", null);
            return resp;
        }
    }

    /**
     * 验证验证码
     *
     * @param verifyCheckCodeInputModel
     * @return
     */
    @Override
    public RespModel<String> verifyCheckCode(VerifyCheckCodeInputModel verifyCheckCodeInputModel) {
        if (verifyCheckCodeInputModel == null
                || StringUtils.isBlank(verifyCheckCodeInputModel.getId())
                || StringUtils.isBlank(verifyCheckCodeInputModel.getCheckcode())) {
            RespModel<String> resp = new RespModel("failed", "406", "PARAM IS MISSING",null);
            return resp;
        }

        ExpiringMap<String, CheckCodeModel> map = ExpiringMapUtil.expiringMap;

        if (!map.containsKey(verifyCheckCodeInputModel.getId())) {
            RespModel<String> resp = new RespModel("failed", "404","CHECKCODE IS OUTDATED", null);
            return resp;
        }
        if (map.get(verifyCheckCodeInputModel.getId()).getCheckcode().equals(verifyCheckCodeInputModel.getCheckcode())) {
            if(!StringUtils.isBlank(verifyCheckCodeInputModel.getPhone())){
                if (!map.get(verifyCheckCodeInputModel.getId()).getId().equals(verifyCheckCodeInputModel.getPhone())) {
                    return new RespModel("failed", "405","THE PHONE OF RECEVIE CHECKCODE IS DIFFERENT WITH USERNAME",
                            null);
                }
            }
            RespModel<String> resp = new RespModel("success", "", "","CHECKCODE IS CORRECT");
            return resp;
        }
        RespModel<String> resp = new RespModel("failed", "403", "CHECKCODE IS WRONG",null);
        return resp;
    }

    public String getSMS_MSG_PREFIX() {
        return SMS_MSG_PREFIX;
    }

    public void setSMS_MSG_PREFIX(String sMS_MSG_PREFIX) {
        SMS_MSG_PREFIX = sMS_MSG_PREFIX;
    }

    public String getSMS_MSG_MIDDLE() {
        return SMS_MSG_MIDDLE;
    }

    public void setSMS_MSG_MIDDLE(String sMS_MSG_MIDDLE) {
        SMS_MSG_MIDDLE = sMS_MSG_MIDDLE;
    }

    public String getSMS_MSG_SUFFIX() {
        return SMS_MSG_SUFFIX;
    }

    public void setSMS_MSG_SUFFIX(String sMS_MSG_SUFFIX) {
        SMS_MSG_SUFFIX = sMS_MSG_SUFFIX;
    }

    public String getLOCK_WAITTIME() {
        return LOCK_WAITTIME;
    }

    public void setLOCK_WAITTIME(String lOCK_WAITTIME) {
        LOCK_WAITTIME = lOCK_WAITTIME;
    }

    public String getSMSURL() {
        return SMSURL;
    }

    public void setSMSURL(String sMSURL) {
        SMSURL = sMSURL;
    }
}
